<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import Stats from "three/examples/jsm/libs/stats.module";
import {Lensflare, LensflareElement} from "three/examples/jsm/objects/Lensflare";
import { ref, onMounted } from "vue";
import {or} from "three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements";

// 画布
const canvas = ref<any>();
// 场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.set(-20, 10, 45);
camera.lookAt(10, 0, 0);
// 渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x000000);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 相机控件
const orbitControl = new OrbitControls(camera, renderer.domElement);
// 性能统计
const stat = Stats();
// plane
const texture = new THREE.TextureLoader().load(new URL("@/assets/textures/ground/grasslight-big.jpg", import.meta.url).href);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(10, 10);
const planeGeometry = new THREE.PlaneGeometry(1000, 1000, 20, 20);
const planeMaterial = new THREE.MeshLambertMaterial({
  map: texture
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
plane.rotateX(-0.5 * Math.PI);
plane.position.set(15, 0, 0);
scene.add(plane);
// cube
const cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
const cubeMaterial = new THREE.MeshLambertMaterial({
  color: 0xff3333,
});
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
cube.position.set(4, 3, 0);
scene.add(cube);
// sphere
const sphereGeometry = new THREE.SphereGeometry(4, 25, 25);
const sphereMaterial = new THREE.MeshLambertMaterial({
  color: 0x7777ff,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.castShadow = true;
sphere.position.set(10, 0, 10);
scene.add(sphere);
// ambient light
const ambient = new THREE.AmbientLight("#1c1c1c");
scene.add(ambient);
// spot light
const spot = new THREE.SpotLight(0xcccccc);
spot.position.set(-40, 60, -10);
spot.lookAt(plane.position);
scene.add(spot);
// target
const target = new THREE.Object3D();
target.position.set(5, 0, 0);
// spot light
const spotLight = new THREE.DirectionalLight("#ffffff");
spotLight.position.set(30, 10, -50);
spotLight.castShadow = true;
spotLight.target = plane;
spotLight.shadow.camera.near = 0.1;
spotLight.shadow.camera.far = 100;
spotLight.shadow.camera.left = -100;
spotLight.shadow.camera.right = 100;
spotLight.shadow.camera.top = 100;
spotLight.shadow.camera.bottom = -100;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;

// 镜头光晕纹理
const textureFlare0 = new THREE.TextureLoader().load(new URL("@/assets/textures/flares/lensflare0.png", import.meta.url).href);
const textureFlare3 = new THREE.TextureLoader().load(new URL("@/assets/textures/flares/lensflare3.png", import.meta.url).href);

const flareColor = new THREE.Color(0xffaacc);
// 镜头光晕
const lensFlare = new Lensflare();
lensFlare.addElement(new LensflareElement(textureFlare0, 350, 0.0, flareColor));
lensFlare.addElement(new LensflareElement(textureFlare3, 60, 0.6, flareColor));
lensFlare.addElement(new LensflareElement(textureFlare3, 70, 0.7, flareColor));
lensFlare.addElement(new LensflareElement(textureFlare3, 120, 0.9, flareColor));
lensFlare.addElement(new LensflareElement(textureFlare3, 70, 1.0, flareColor));
spotLight.add(lensFlare);

scene.add(spotLight);
// gui
let step = 0;
const controlObj = {
  rotationSpeed : 0.03,
  bouncingSpeed : 0.03,
  ambientColor : ambient.color.getStyle(),
  pointColor : spotLight.color.getStyle(),
  intensity : 0.1,
  distance : 0,
  exponent : 30,
  angle : 0.1,
  debug : false,
  castShadow : true,
  onlyShadow : false,
  target : "Plane",
};
const gui = new GUI();
gui.addColor(controlObj, 'ambientColor').onChange(function (e) {
  ambient.color = new THREE.Color(e);
});

gui.addColor(controlObj, 'pointColor').onChange(function (e) {
  spotLight.color = new THREE.Color(e);
});
// @ts-ignore
gui.add(controlObj, 'intensity', 0, 5).onChange(function (e) {
  spotLight.intensity = e;
});

const render = () => {
  stat.update();
  orbitControl.update();

  cube.rotation.x += controlObj.rotationSpeed;
  cube.rotation.y += controlObj.rotationSpeed;
  cube.rotation.z += controlObj.rotationSpeed;

  step += controlObj.bouncingSpeed;
  sphere.position.x = 20 + (10 * (Math.cos(step)));
  sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));

  requestAnimationFrame(render);
  renderer.render(scene, camera);
};

onMounted(() => {
  canvas.value.appendChild(stat.domElement);
  canvas.value.appendChild(renderer.domElement);

  render();
});

</script>